# This file is part of OrangeSpider. OrangeSpider is a meta model based
# development tool.
# 
# OrangeSpider is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# OrangeSpider is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with OrangeSpider.  If not, see <http://www.gnu.org/licenses/>.
#
# Copyright 2009 Stefan Nikolaus <OrangeSpiderMaster@googlemail.com>

from MetaModel import *
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import Component
from Ui import *

"""
LevelDesc for SpiderFILE
Root,        Navigator,           Selector,                 Header
METACLASS,   "Extension",         RootFolderId,             ""
CLASS,       "OutgoingClasses",   "Folder.Contains.Folder", "<AllFolders>"
CLASS,       "OutgoingClasses",   "Folder.Contains.Files",  "<AllFiles>"
"""

class LevelDesc:
   Header = 1
   Data = 2
   def __init__(self, parentLevel):
      self.childLevels = []
      if parentLevel:
          parentLevel.childLevels.append(self)
  
class DataLevelDesc(LevelDesc):
   def __init__(self, parentLevel, rootType, navigator, selector):
      LevelDesc.__init__(self, parentLevel)
      self.rootType = rootType
      self.navigator = navigator
      self.selector = selector
      self.type = LevelDesc.Data

class HeaderLevelDesc(LevelDesc):
   def __init__(self, parentLevel, headerText):
      LevelDesc.__init__(self, parentLevel)
      self.headerText = headerText
      self.type = LevelDesc.Header



# Part of a tree level for displaying a list of data
class DataPartition:
   def __init__(self, root, levelDesc):
      assert(levelDesc.type == LevelDesc.Data)
      self.viewData = root.outgoing[levelDesc.selector]
      self.keys = self.viewData.keys()
      self.navigator = levelDesc.navigator
      self.selector = levelDesc.selector
      self.dataSelection = Table.DataFromTarget
      self.header = "Name"
      self.levelDesc = levelDesc
   def length(self):
      return len(self.keys)

# Part of a tree level for displaying only one text
class HeaderPartition:
   def __init__(self, levelDesc):
      self.levelDesc = levelDesc
   def length(self):
      return 1

class TreeItem:
   #ViewDataRole = Qt.UserRole
   KeyDataRole = Qt.UserRole + 1

   id = 0
   def __init__(self, parent, root, levelDesc):
      self.parent = parent
      self.id = TreeItem.id
      TreeItem.id += 1
      self.root = root
      self.children = []       # Create new treeitems on the fly
      self.partitions = []
      self.levelDesc = levelDesc  # Description of our current level of view in the tree
      for subLevelDesc in levelDesc.childLevels:
          if subLevelDesc.type == LevelDesc.Header:
              partition = HeaderPartition(subLevelDesc)
          else:
              partition = DataPartition(root, subLevelDesc)
          self.partitions.append(partition)
          # none indicated a non existend tree item
          self.children.extend([None for x in range(partition.length()) ] )  

   def data(self, column, role):         # wird verwendet in data
      if role == Qt.DisplayRole:
          if column == 0:
              if self.levelDesc.type == LevelDesc.Data:
                  return QVariant(self.root["Name"])
              else:
                  return QVariant(self.levelDesc.headerText)
          else:
              if self.levelDesc.type == LevelDesc.Data:
                  if "Type" in self.root.intention.metaProperties:
                      return QVariant(self.root["Type"])
          return QVariant()

      elif role == TreeItem.KeyDataRole:
          if self.levelDesc.type == LevelDesc.Data:
              return self.root
          else:
              return self.root
      else:
          return QVariant()

   def row(self):                  # wird verwendet fuer parent: in createIndex als row nr.
      if self.parent:
          return self.parent.children.index(self)
    
   def getChild(self, row):        # Wird verwendet fuer Model.index: -> createIndex mit treeItem
      childItem = self.children[row] 
      if not childItem:
          (partition, partitionRow) = self._getPartition(row)
          if partition.levelDesc.type == LevelDesc.Header:
              childItem = TreeItem(self, self.root, partition.levelDesc)
          elif partition.levelDesc.type == LevelDesc.Data:
              key = partition.keys[partitionRow]
              if partition.dataSelection == Table.DataFromTarget:
                  child = partition.viewData[key].target
              else:
                  assert(0)
              childItem = TreeItem(self, child, partition.levelDesc)
          else:
              assert(0)
          self.children[row] = childItem
      return childItem

   def childCount(self):
      return len(self.children)

   def _getPartition(self, row):
      # Wird benoetigt, weil in einem Level mehrere Listen angezeigt werden koennen
      currentRow = row
      for partition in self.partitions:
         if partition.length() > currentRow:
             return (partition, currentRow)
         currentRow -= partition.length()
      assert(0)
      return (None, 0)

class TreeModel(QAbstractItemModel):
  def __init__(self):
      QAbstractItemModel.__init__(self)
      self.rootItem = None

  #def dropMimeData(data, action, row, column, parent):
  #    print "dropMimeData", action, row, column

  def rowCount(self, parent = None):
      #print "row"
      if self._isRootIndex(parent):
          return self.rootItem.childCount()
      else:
          return parent.internalPointer().childCount()

  def columnCount(self, parent = None):
      #print "col"
      return 1

  def data(self, index, role):
      #print "data"
      if role == Qt.DisplayRole or role == TreeItem.KeyDataRole:
          #print "data", index.row(), index.column()
          if index.isValid():
              item = index.internalPointer()
              return item.data(index.column(), role)
      return QVariant()

  def headerData(self, section, orientation, role):
      #print "headerData"
      if role == Qt.DisplayRole:
          return QVariant("Header")
      return QVariant()

  def index(self, row, column, parent = None):
      #print "index", row, column
      if self._isRootIndex(parent):
          parentItem = self.rootItem
      else:
          parentItem = parent.internalPointer()

      childItem = parentItem.getChild(row)

      if childItem:
          return self.createIndex(row, column, childItem)
      else:
          return QtCore.QModelIndex()

  def parent(self, index):
      #print "parent of", index.row(), index.column()
      if self._isRootIndex(index):
          return QModelIndex()
      childItem = index.internalPointer()
      parentItem = childItem.parent

      if parentItem == self.rootItem:
          return QModelIndex()

      return self.createIndex(parentItem.row(), 0, parentItem)

  def resetAll(self):
      print "resetAll"
      QAbstractItemModel.reset(self)

  def _isRootIndex(self, index):
      return not index.isValid()

  #def dropMimeData(self, data, action, row, column, parent):
  #    print "dropMimeData"

  #def supportedDropActions(self):
  #    print "supportedDropActions"
  #    return Qt.CopyAction | Qt.MoveAction

  #def flags(self, index):
  #   print "flags"
  #   if index.isValid():
  #      f = Qt.ItemIsDragEnabled | Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsDragEnabled
  #   else:
  #      f = Qt.ItemIsDragEnabled | Qt.ItemIsSelectable | Qt.ItemIsEnabled
  #   return f

class RepositoryTreeView(QTreeView):
   def __init__(self, rootItem, rootDesc, parent = None):
       QTreeView.__init__(self, parent)
       self.treeModel = TreeModel()
       self.treeModel.rootItem = TreeItem(None, rootItem, rootDesc)
       self.rootDesc = rootDesc
       self.rootItem = rootItem
       self.setModel(self.treeModel)
       self.header().hide()
       self.setAcceptDrops(True)
       self.setDragEnabled(True)
       self.setDropIndicatorShown(True)

   def resetView(self):
       self.treeModel = TreeModel()
       self.treeModel.rootItem = TreeItem(None, self.rootItem, self.rootDesc)
       self.setModel(self.treeModel)

   def dragEnterEvent(self, event):
       print "dragEnterEvent"
       event.acceptProposedAction()

   def dragMoveEvent(self, event):
       #print "dragMoveevent"
       #event.acceptProposedAction()
       pass

   def dragEnterEvent(self, event):
      #print event.mimeData()
      #print event.mimeData().hasFormat("text/plain")
      #event.accept()
      pass

   def dropEvent(self, event):
      #for s in event.mimeData().formats():
      #   print s
      #print "Dropped"
      #event.accept()
      pass
      
def _demoTree():
    di = Component.DirectoryImporter()
    #di.read("C:/SWSETUP", ""7)
    #di.read("C:/Program Files/Common Files", "")
    di.read("D:/Users/sn/Development/Test", "")
    r = di.repository
    r.watcher = Watcher()
    r.watcher.addListener(Emitter(), "Emitter")
    print len(r.metaClasses["Folder"].extension)
    print len(r.metaClasses["File"].extension)
    for folder in r.eachClass("Folder"):
        if len(folder.incoming["Folder.Contains.Folder"] ) == 0:
            rootFolder = folder
            break

    #r = buildMetaModel("T","SpiderFILE", Watcher())
    #r.watcher.emitter = Emitter()
    #rootFolder = r.Class("Folder")
    #rootFolder["Name"] = "Root"
    #f = r.Class("Folder")
    #f["Name"] = "Sub"
    #r.Assoc(rootFolder, f, "Contains")


    if rootFolder:
        dlg = QDialog()
        model = TreeModel()

        h1 = HeaderLevelDesc(None, "Folder")
        h2 = HeaderLevelDesc(h1, "Folder")
        h3 = DataLevelDesc(h2, Entity.CLASS, "OutgoingClasses", "Folder.Contains.Folder")
        h4 = DataLevelDesc(h2, Entity.CLASS, "OutgoingClasses", "Folder.Contains.File")
        h3.childLevels.append(h3)

        rootItem = TreeItem(None, rootFolder, h1)
        tree = RepositoryTreeView(rootFolder, h1)
        #tree.setModel(model)
        layout = QVBoxLayout()
        layout.addWidget(tree)

        dlg.setLayout(layout)
        dlg.exec_()



if __name__ == "__main__":
    app = QApplication(sys.argv)
    #s = { "a":"b" }
    #QtGui.QMessageBox.critical(None, s["a"],
    #                           "Unable to start the test: %1.")

    #di = Component.DirectoryImporter()
    #di.read("C:\\Windows", "")
    
    _demoTree()
    
    sys.exit(0)

